package com.syh.jn.scm.service.impl.supplier.finance;

import cn.redscarf.commons.wrapper.Restrictions;
import cn.redscarf.commons.wrapper.Wrapper;
import com.alibaba.dubbo.config.annotation.Service;
import com.syh.core.ddd.event.annotation.DomainEventHandle;
import com.syh.core.ddd.infrastructure.repository.AggregateRepository;
import com.syh.core.ddd.service.AbstractServiceImpl;
import com.syh.jn.scm.domain.operation.entity.supplier.OperaSupplier;
import com.syh.jn.scm.domain.operation.event.supplier.OperaSupplierEvent;
import com.syh.jn.scm.domain.supplier.entity.finance.CostBill;
import com.syh.jn.scm.domain.supplier.entity.finance.StatementAccountBill;
import com.syh.jn.scm.domain.supplier.event.CostBillEvent;
import com.syh.jn.scm.domain.supplier.event.finance.StatementAccountBillEvent;
import com.syh.jn.scm.domain.supplier.repository.finance.CostBillRepository;
import com.syh.jn.scm.dto.supplier.finance.CostBillMto;
import com.syh.jn.scm.dto.supplier.finance.CostBillSto;
import com.syh.jn.scm.dto.supplier.finance.CostBillVo;
import com.syh.jn.scm.dto.support.FilesDto;
import com.syh.jn.scm.service.api.supplier.finance.CostBillService;
import com.syh.jn.scm.service.api.supplier.finance.enums.CostBillEnums;
import com.syh.jn.scm.service.api.supplier.finance.enums.StatementAccountBillEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * 费用单接口实现
 */
@Service
@Transactional
public class CostBillServiceImpl extends AbstractServiceImpl<CostBillSto, CostBillMto, CostBillVo, CostBill, Long> implements CostBillService {

  @Autowired
  private CostBillRepository costBillRepositoryImpl;

  @Override
  protected AggregateRepository<CostBill, Long> getAggregateRepository() {
    return costBillRepositoryImpl;
  }

  /**
   * 保存费用单
   *
   * @param sto
   * @return
   */
  @Override
  public Long save(CostBillSto sto) {
    CostBill bill = CostBill.createCostBill(sto);
    Long id = costBillRepositoryImpl.add(bill);
    return id;
  }

  /**
   * 修改费用单
   *
   * @param mto
   */
  @Override
  public void update(CostBillMto mto) {
    CostBill bill = costBillRepositoryImpl.getById(mto.getId());
    bill.modify(mto);
    costBillRepositoryImpl.update(bill);
  }

  /**
   * 删除费用单
   *
   * @param id
   */
  @Override
  public void delete(Long id) {
    CostBill bill = costBillRepositoryImpl.getById(id);
    bill.destroy();
    costBillRepositoryImpl.remove(bill);
  }

  /**
   * 确认费用单
   *
   * @param id
   */
  @Override
  public void confirm(Long id) {
    CostBill bill = costBillRepositoryImpl.getById(id);
    bill.confirm();
    costBillRepositoryImpl.update(bill);

    //在事件里面做了双方确认(意思就是双方确认之后才纳入应收付记录和汇总)
    if (bill.getState().equals(CostBillEnums.State.CONFIRM.getStatus()) && bill.getConfirmState().equals(CostBillEnums.ConfirmState.CONFIRM.getStatus())) {
      Object[] obj = new Object[]{bill};
      //发送事件消息
      this.publicEvent(CostBillEvent.buildStateConfirm(obj));
    }
  }

  /**
   * 取消确认费用单
   *
   * @param id
   */
  @Override
  public void cancelConfirm(Long id) {
    CostBill bill = costBillRepositoryImpl.getById(id);
    bill.cancelConfirm();
    costBillRepositoryImpl.update(bill);
    if (bill.getConfirmState().equals(CostBillEnums.ConfirmState.CONFIRM.getStatus())
            //或者客户类型是物流的时候
            || bill.getCustomerType() == 2) {
      Object[] obj = new Object[]{bill};
      //发送事件消息
      this.publicEvent(CostBillEvent.buildStateUnConfirm(obj));
    }
  }

  /**
   * 取消费用单
   *
   * @param id
   */
  @Override
  public void cancel(Long id) {
    CostBill bill = costBillRepositoryImpl.getById(id);
    bill.cancel();
    costBillRepositoryImpl.update(bill);

    Object[] obj = new Object[]{bill};
  }


  /**
   * 上传单据图片
   *
   * @param dto
   */
  @Override
  public void upload(FilesDto dto) {
    CostBill bill = costBillRepositoryImpl.getById(dto.getId());
    bill.uploadImages(dto);
    costBillRepositoryImpl.upload(bill);
  }

  /**
   * 消费者：监听对账单（生成对账单状态和对账单号）
   *
   * @param bill
   */
  @DomainEventHandle(StatementAccountBillEvent.STATEMENT_BILL_ACCOUNT_CREATED)
  protected void handleStatementBillAccountCreated(StatementAccountBill bill) {
    bill.getStatementAccountBillItems().forEach(billItem -> {
      if (billItem.getSourceType().equals(StatementAccountBillEnum.SOURCE_COST_BILL.getStatus())) {
        CostBill costBill = costBillRepositoryImpl.getById(billItem.getSourceId());
        costBill.generatingStatementAc(bill.getId());
        costBillRepositoryImpl.update(costBill);
      }
    });
  }

  /**
   * 消费者：监听对账单（修改对账单状态）
   *
   * @param bill
   */
  @DomainEventHandle(StatementAccountBillEvent.STATEMENT_BILL_ACCOUNT_UPDATA)
  protected void handleStatementBillAccountUpdata(StatementAccountBill bill) {
    Wrapper wrapper = Wrapper.build();
    wrapper.append(Restrictions.eq("statementOfAccountId", bill.getId()));
    List<CostBill> costBills = costBillRepositoryImpl.getList(wrapper);
    costBills.forEach(costBill -> {
      costBill.deleteStatementAc();
      costBillRepositoryImpl.update(costBill);
    });
    bill.getStatementAccountBillItems().forEach(billItem -> {
      if (billItem.getSourceType().equals(StatementAccountBillEnum.SOURCE_COST_BILL.getStatus())) {
        CostBill costBill = costBillRepositoryImpl.getById(billItem.getSourceId());
        costBill.generatingStatementAc(bill.getId());
        costBillRepositoryImpl.update(costBill);
      }
    });
  }

  /**
   * 消费者：监听对账单（删除对账单状态和对账单号）
   *
   * @param bill
   */
  @DomainEventHandle(StatementAccountBillEvent.STATEMENT_BILL_ACCOUNT_DESTROY)
  protected void handleStatementBillAccountDestroy(StatementAccountBill bill) {
    bill.getStatementAccountBillItems().forEach(billItem -> {
      if (billItem.getSourceType().equals(StatementAccountBillEnum.SOURCE_COST_BILL.getStatus())) {
        CostBill costBill = costBillRepositoryImpl.getById(billItem.getSourceId());
        costBill.deleteStatementAc();
        costBillRepositoryImpl.update(costBill);
      }
    });
  }

  /**
   * 消费者：监听服务商反开账（删除所有该服务商的费用单）
   */
  @DomainEventHandle(OperaSupplierEvent.SUPPLIER_REVERSAL_ACCOUNT)
  protected void handleSupplierReversalAccount(OperaSupplier supplier) {
    this.costBillRepositoryImpl.deleteByBusinessEntityId(supplier.getId());
  }

}
